/*
 * fork函数在创建一个子进程时，子进程就会继承父进程的环境和上下文大部分内容的一份拷贝
 * 包括信号状态、调度参数和文件描述符表。
 * 继承的含义并不总是那么明显，由于子进程在被创建时会收到其父进程描述符表的一份拷贝，因此，
 * 对于在创建子进程前就打开的文件来说，父进程和子进程将共享同一个文件偏移量
 *
 **/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>

int main(void) {
    char c = '!';
    int myfd, fork_fd;

    if ( (myfd = open("aaaa.dat", O_RDWR | O_APPEND)) == -1) {
        perror("Failed to open file");
        return -1;
    }

    fork_fd = fork();
    if ( fork_fd == -1) {
        perror("Failed to fork");
        return -1;
    }

    // 子进程出处函数
    if (fork_fd == 0) {
        char buf[] = "Hello, this is son!\n";
        int ret = write(myfd, buf, sizeof(buf));
        if ( ret == -1) {
            perror("write error");
            return -1;
        } else {
            printf("%s write succ\n", buf);
        }
    } else {
        char buf[] = "Hello, this is parent!\n";
        int ret = write(myfd, buf, sizeof(buf));
        if (ret == -1) {
            perror("write error");
            return -1;
        } else {
            printf("%s write succ\n", buf);
        }
    }
    //read(myfd, &c, 1);

    //printf("Process %ld got %c\n", (long)getpid(), c);
    close(myfd);

    // 由于缓冲的存在，printf函数的输出很可能会被写入到stdout对应的缓冲区中，而不是实际的输出设备。
    // 这个缓冲区是用户空间的一部分，因此它会被fork函数复制，当父进程和子进程终止时，main函数的返回就会将缓冲区刷新作为清理的一部分
    // 因此输出为 This is my output.This is my output.
    // printf("This is my output.");
    // fork();

    // 由于标准输出的缓冲都是行缓冲，这意味着当缓冲区包含换行符时，他就会被刷新。
    // 由于在这种情况下输出了一个换行符，因此缓冲区可能在fork函数前被刷新并且只有一行输出 This is my output.
    // printf("This is myoutput.\n");
    // fork();

    return 0;
}